﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Schema;

namespace xmlint
{
    class Catalog
    {
        Uri baseUri;
        NameTable nt;
        XmlSchemaSet sc;
        Dictionary<Uri, XmlSchema> map;

        public Catalog()
        {
            nt = new NameTable();
            sc = new XmlSchemaSet(nt);
            map = new Dictionary<Uri, XmlSchema>();
            baseUri = new Uri(Directory.GetCurrentDirectory() + "\\");
        }

        public void Add(string uri)
        {
            Uri resolved = new Uri(baseUri, uri);
            using (XmlReader reader = XmlReader.Create(resolved.AbsoluteUri))
            {
                XmlSchema s = XmlSchema.Read(reader, (sender, args) =>
                {
                    Console.WriteLine("Error loading schema: " + uri + "\n    " + args.Message);
                });

                map[resolved] = s;

                sc.Add(s);
            }
        }

        public XmlNameTable NameTable { get { return nt; } }

        public XmlSchemaSet SchemaSet { get { return sc; } set { sc = value; }}

        internal void Load(string fileName)
        {
            try
            {
                Uri baseUri = new Uri(System.IO.Path.GetFullPath(fileName));
                XDocument doc = XDocument.Load(fileName);
                XNamespace docns = doc.Root.Name.Namespace;
                foreach (XElement uri in doc.Root.Elements(docns + "uri"))
                {
                    string ns = (string)uri.Attribute("name");
                    string rel = (string)uri.Attribute("uri");

                    Uri resolved = new Uri(baseUri, rel);
                    Add(resolved.AbsoluteUri);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error loading catalog: " + ex.Message);
            }
        }

        internal void Save(string fileName)
        {
            /*
             * <catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" prefer="public">
                     <uri name="http://apache.org/xml/xcatalog/example" uri="example.xsd"/>
                </catalog>
             */
            try
            {
                XNamespace ns = XNamespace.Get("urn:oasis:names:tc:entity:xmlns:xml:catalog");
                XDocument doc = new XDocument(
                    new XElement(ns + "catalog", new XAttribute("prefer", "public")));

                foreach (KeyValuePair<Uri, XmlSchema> pair in map)
                {
                    Uri uri = pair.Key;
                    Uri rel = this.baseUri.MakeRelativeUri(uri);
                    string rels = rel.GetComponents(UriComponents.SerializationInfoString, UriFormat.SafeUnescaped);

                    XmlSchema s = pair.Value;
                    doc.Root.Add(new XElement(ns + "uri", new XAttribute("name", s.TargetNamespace),
                        new XAttribute("uri", rels)));
                }

                doc.Save(fileName);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error saving catalog: " + ex.Message);
            }

        }
    }
}
